package cn.edu.buaa.treehole.service;

import cn.edu.buaa.treehole.config.Setting;
import cn.edu.buaa.treehole.common.cache.CachedFactory;
import cn.edu.buaa.treehole.common.cache.CachedMap;
import cn.edu.buaa.treehole.dao.PostDao;
import cn.edu.buaa.treehole.dao.ReplyDao;
import cn.edu.buaa.treehole.dao.SignatureDao;
import cn.edu.buaa.treehole.dao.exception.*;
import cn.edu.buaa.treehole.pojo.PostInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class PostInfoService {
    private final int postCacheSize = 32;

    private class CacheFactory implements CachedFactory<Long, PostInfo> {

        @Override
        public PostInfo get(Long pid) throws Exception {
            return postDao.getPost(pid);
        }
    }

    private final CachedMap<Long, PostInfo> cache
            = new CachedMap<Long, PostInfo>(
                new CacheFactory(),
                (Long pid, PostInfo info) -> { },
                postCacheSize
    );
    private final Logger logger = LoggerFactory.getLogger(PostInfoService.class);
    private final PostDao postDao;
    private final ReplyDao replyDao;
    private final SignatureDao signatureDao;
    private ReplyInfoService replyInfoService;
    private PostListService postListService;
    private NameService nameService;
    private Setting setting;

    @Autowired
    public PostInfoService(
            PostDao postDao,
            ReplyDao replyDao,
            SignatureDao signatureDao
    ) {
        this.postDao = postDao;
        this.replyDao = replyDao;
        this.signatureDao = signatureDao;
    }

    @Autowired
    public void setReplyInfoService(ReplyInfoService replyInfoService) {
        this.replyInfoService = replyInfoService;
    }

    @Autowired
    public void setPostListService(PostListService postListService) {
        this.postListService = postListService;
    }

    @Autowired
    public void setNameService(NameService nameService) {
        this.nameService = nameService;
    }

    @Autowired
    public void setSetting(Setting setting) {
        this.setting = setting;
    }

    public Setting getSetting() {
        return setting;
    }

    @Override
    public String toString() {
        return "PostInfoService{" +
                "postCacheSize=" + postCacheSize +
                ", cache=" + cache +
                ", postDao=" + postDao +
                ", replyDao=" + replyDao +
                ", signatureDao=" + signatureDao +
                ", replyInfoService=" + replyInfoService +
                '}';
    }

    /*
    * @param postInfo: pid不必设置.
    * */
    public long addPost(PostInfo postInfo) throws PidHasExistException, DaoException {
        long pid = postDao.getLatestPostPid();
        postInfo.setPid(++pid);
        System.out.println(postInfo.getPid()+postInfo.getSignature());
        try {
            signatureDao.addName(postInfo.getPid(), postInfo.getSignature(), nameService.getName(0));
        }
        catch (SignatureHasExistException | NameHasExistException e) {
            String msg = toString() + ".addPost(" + postInfo + ")";
            logger.error(msg, e);
            throw new RuntimeException(msg, e);
        }
        System.out.println("finish add name");
        postDao.addPost(postInfo);
        System.out.println("finish add post");
        //postListService.addPostCache(pid);
        System.out.println("finish add post cache");
        return pid;
    }

    public void deletePost(long pid, String signature) throws SignatureNotExistException, DaoException {
        PostInfo info = postDao.getPost(pid);
        System.out.println("finish get post id");
        System.out.println(pid+" "+signature);
        if (!signature.equals("admin") && !info.getSignature().equals(signature)) {
            throw new SignatureNotExistException(toString() +
                    ".deletePost(" + pid + ", " + signature + ")");
        }
        System.out.println(!setting.blockInfoCache());
        if (!setting.blockInfoCache()) {
            try {
                cache.remove(pid, false);
            } catch (DaoException e) {
                throw e;
            } catch (Exception e) {
                String msg = toString() + ".deletePost(" + pid + ", " + signature + ")";
                logger.error(msg, e);
                throw new RuntimeException(msg, e);
            }
        }
        replyInfoService.deleteAllReplyCacheForPost(pid);
        System.out.println("finish eleteAllReplyCacheForPost");
        postDao.deletePost(pid);
        System.out.println("finish deletePost(pid)");
        postListService.deletePostCache(pid);
        System.out.println("finish deletePostCache(pid)");
    }

    public PostInfo getPostInfo(long pid) throws PidNotExistException, DaoException {
        if (setting.blockInfoCache()) { //setting.blockInfoCache()
            return postDao.getPost(pid);
        }
        try {
            return cache.get(pid);
        }
        catch (DaoException e) {
            throw e;
        }
        catch (Exception e) {
            String msg = toString() + ".getReplyInfo(" + pid + ")";
            logger.error(msg, e);
            throw new RuntimeException(msg, e);
        }
    }

    public int getRepliesCount(long pid) throws PidNotExistException, DaoException {
        return replyDao.getRepliesCount(pid);
    }
}
